package cn.itcast.nems.oldems.service.impl;

import cn.itcast.nems.base.dao.entity.City;
import cn.itcast.nems.base.dao.entity.Province;
import cn.itcast.nems.base.dao.mapper.CityMapper;
import cn.itcast.nems.base.dao.mapper.ProvinceMapper;
import cn.itcast.nems.base.dto.CityDto;
import cn.itcast.nems.base.dto.ProvinceDto;
import cn.itcast.nems.manager.redis.RedisUtil;
import cn.itcast.nems.oldems.service.GeoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Service
@RequiredArgsConstructor
public class GeoServiceImpl implements GeoService {

    private final ProvinceMapper provinceMapper;
    private final CityMapper cityMapper;
    private final RedisUtil redisUtil;
    private final ObjectMapper objectMapper = new ObjectMapper()
            .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
            .configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);

    List<ProvinceDto> loadData() {
        var provinces = provinceMapper.selectList(new QueryWrapper<>());
        var cities = cityMapper.selectList(new QueryWrapper<>());
        var result = new ArrayList<ProvinceDto>();
        var provinceMap = new HashMap<String, ProvinceDto>();
        for (Province province : provinces) {
            var provinceDto = new ProvinceDto();
            provinceDto.setCode(province.getCode());
            provinceDto.setCnName(province.getCnName());
            provinceDto.setCityList(new ArrayList<>());
            provinceMap.put(province.getCode(), provinceDto);
            result.add(provinceDto);
        }
        for (City city : cities) {
            var cityDto = new CityDto();
            cityDto.setIdcardCode(city.getIdcardCode());
            cityDto.setCityName(city.getCityName());
            cityDto.setProvinceCode(city.getProvinceCode());
            var p = provinceMap.get(city.getProvinceCode());
            if (p != null) {
                p.getCityList().add(cityDto);
            }
        }
        return result;

    }

    @Override
    public List<ProvinceDto> listProvinceAndCities() throws Exception {
        var key = "NEMS:BASE:GEO:ALL";
        var cacheJson = (String) redisUtil.get(key);
        if (StringUtils.hasText(cacheJson)) {
            return objectMapper.readValue(
                    cacheJson,
                    objectMapper.getTypeFactory().constructCollectionType(List.class, ProvinceDto.class)
            );
        }
        var data = loadData();
        cacheJson = objectMapper.writeValueAsString(data);
        redisUtil.set(key, cacheJson, 3600);
        return data;
    }

}
